#ifndef __UDSF_SPIFLASH_C__
#define __UDSF_SPIFLASH_C__


#include "app.h"
/*
*   notice:
*   UDSF 同UDF编程：不可调用cstd-lib,只可调用"sdk_ifs_udk_cfg.h"、"sys_api.h"中列出的API函数。
*   UDSF文件内函数均需使用static修饰符，且UDF中以#include "udsf_xxx.c"形式引用
*/


/*qspi*/
#define QSPI_READ_CMD_STANDARD             (0x0Bul)
#define QSPI_READ_CMD_DUAL_IO              (0xBBul)
#define QSPI_READ_CMD_QUAD_IO              (0xEBul)
#define QSPI_READ_CMD_DUAL_OUTPUT          (0x3Bul)	
#define QSPI_READ_CMD_QUAD_OUTPUT          (0x6Bul)

//#define QSPI_DUMMY_DATA_LEN_STANDARD       (0x07ul)
//#define QSPI_DUMMY_DATA_LEN_DUAL_IO        (0x03ul)
//#define QSPI_DUMMY_DATA_LEN_QUAD_IO        (0x05ul)
//#define QSPI_DUMMY_DATA_LEN_DUAL_OUTPUT    (0x07ul)
//#define QSPI_DUMMY_DATA_LEN_QUAD_OUTPUT    (0x07ul)

#if defined( USE_SF_TJ25Q80MA )
#define QSPI_DUMMY_DATA_LEN_STANDARD       (0x07ul)
#define QSPI_DUMMY_DATA_LEN_DUAL_IO        (0x07ul) 
#define QSPI_DUMMY_DATA_LEN_QUAD_IO        (0x07ul)
#define QSPI_DUMMY_DATA_LEN_DUAL_OUTPUT    (0x07ul)
#define QSPI_DUMMY_DATA_LEN_QUAD_OUTPUT    (0x07ul)
#else
#define QSPI_DUMMY_DATA_LEN_STANDARD       (0x07ul)
#define QSPI_DUMMY_DATA_LEN_DUAL_IO        (0x03ul)
#define QSPI_DUMMY_DATA_LEN_QUAD_IO        (0x05ul)
#define QSPI_DUMMY_DATA_LEN_DUAL_OUTPUT    (0x07ul)
#define QSPI_DUMMY_DATA_LEN_QUAD_OUTPUT    (0x07ul)
#endif

#define	QSPI_BOOT_SEL_BOOT             (0x01ul)
#define	QSPI_BOOT_SEL_NORMAL           (0x00ul)	
#define	QSPI_CPOL                      (0x00ul)	
#define	QSPI_CPHA                      (0x00ul)
#define QSPI_CS_CS_LOW                 (0x00ul)	
#define QSPI_CS_CS_HIGH                (0x01ul)

//qspi flash cmd
#define WRITE_DISABLE                  (0x04)
#define WRITE_ENABLE                   (0x06)
#define CHIP_ERASE                     (0x60)
#define READ_REG1                      (0x05)
#define READ_REG2                      (0x35)
#define WRITE_REG_ENABLE               (0x50)
#define WRITE_REG1                     (0x01)
#define DEEP_PD                        (0xB9)

#define SECTOR_ERASE                   (0x20)
#define PAGE_PROGRAM                   (0x02)
#define READ_DATA                      (0x03)
#define REG1_BUSY_MASK                 (0x01)

#define READ_DATA_DUAL_OUTPUT          (0x3B)
#define READ_DATA_QUAD_OUTPUT          (0x6B)
#define READ_DATA_DUAL_IO              (0xBB)
#define READ_DATA_QUAD_IO              (0xEB)

#define SECURITY_ERASE                 (0x44)
#define SECURITY_PP                    (0x42)
#define SECURITY_READ                  (0x48)
#define UUID_READ                      (0x4B)

#define CLK_DIV_FACTOR  (0)

#include "udsf_delay.c"

static uint8_t udsf_qspi_read_cmd(uint8_t cmd)  __attribute__((unused));
static void udsf_qspi_send_cmd(uint8_t cmd) __attribute__((unused));
static void udsf_qspi_send_cmd_subcmd_data(uint8_t cmd,uint32_t subcmd,uint8_t subcmd_len,uint8_t* data,uint32_t data_len,uint8_t data_read_or_write,eQSPI_FLASH_MODE bus_mode) __attribute__((unused));
static void udsf_qspi_set_xip_disable(void) __attribute__((unused));
static void udsf_qspi_set_xip_enable(eQSPI_FLASH_MODE mode) __attribute__((unused));
static void udsf_qspi_xip_mode_set(eQSPI_FLASH_MODE mode) __attribute__((unused));
static void udsf_spiflash_enter_deep_sleep(void) __attribute__((unused));


static void udsf_qspi_xip_mode_set(eQSPI_FLASH_MODE mode){
	udsf_qspi_set_xip_disable();
	udsf_qspi_set_xip_enable(mode);
}

/*qspi*/
static uint8_t udsf_qspi_read_cmd(uint8_t cmd){
	uint8_t res;
	QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_LOW << QSPI_CS_CS_Pos);
	QSPI->DATA8[0] = cmd;         while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->DATA8[0] = QSPI_DUMMY_DATA;   while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
	res = QSPI->DATA8[0];
	return res;
}

static void udsf_qspi_cmd_read_data(uint8_t cmd,uint32_t subcmd,uint8_t subcmd_len,uint8_t* data,uint8_t len){

	QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_LOW << QSPI_CS_CS_Pos);
	QSPI->DATA8[0] = cmd;         while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	for( int i=0;i<subcmd_len;i++ ){
		QSPI->DATA8[0] = ((uint8_t*)&subcmd)[3-i];        while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	}
	for( int i=0;i<len;i++ ){
		QSPI->DATA8[0] = QSPI_DUMMY_DATA;   while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
		data[i] = QSPI->DATA8[0];
	}
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
}

static void udsf_qspi_send_cmd(uint8_t cmd){
	QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_LOW << QSPI_CS_CS_Pos);
	QSPI->DATA8[0] = cmd;         while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
}

static void udsf_qspi_send_cmd_subcmd_data(uint8_t cmd,uint32_t subcmd,uint8_t subcmd_len,uint8_t* data,uint32_t data_len,uint8_t data_read_or_write,eQSPI_FLASH_MODE bus_mode){
	
	QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_LOW << QSPI_CS_CS_Pos);
	QSPI->DATA8[0] = cmd;                                    while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	
	uint32_t dummy_len=0;

	if( data_read_or_write == 0 ){
		if( bus_mode == eQSPI_FLASH_STD){
			if( cmd != READ_DATA ){
				dummy_len = 1;
			}
		}else if( bus_mode == eQSPI_FLASH_DUAL_OUTPUT){
			dummy_len = 1;
		}else if( bus_mode == eQSPI_FLASH_QUAD_OUTPUT){
			dummy_len = 1;
		}else if( bus_mode == eQSPI_FLASH_DUAL_IO ){
			dummy_len = 1;
			QSPI->CTRL = CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos     |
							QSPI_DUAL_OUTPUT  << QSPI_CTRL_FRAME_MODE_Pos;
		}else if( bus_mode == eQSPI_FLASH_QUAD_IO ){
			dummy_len = 3;
			QSPI->CTRL = CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos     |
							QSPI_QUAD_OUTPUT  << QSPI_CTRL_FRAME_MODE_Pos;
		}
	}

	for( int i=0;i<subcmd_len;i++ ){
		QSPI->DATA8[0] = ((uint8_t*)&subcmd)[3-i];        while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	}

	for( int i=0;i<dummy_len;i++ ){
		QSPI->DATA8[0] = QSPI_DUMMY_DATA;             while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	}

	if( data_read_or_write == 0 ){
		if( (bus_mode == eQSPI_FLASH_DUAL_IO) || (bus_mode == eQSPI_FLASH_DUAL_OUTPUT) ){
			QSPI->CTRL = CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos     |
			             QSPI_DUAL_INPUT  << QSPI_CTRL_FRAME_MODE_Pos;
		}else if( (bus_mode == eQSPI_FLASH_QUAD_IO) || (bus_mode == eQSPI_FLASH_QUAD_OUTPUT) ){
			QSPI->CTRL = CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos     |
			             QSPI_QUAD_INPUT  << QSPI_CTRL_FRAME_MODE_Pos;
		}
	}else{
		if( (bus_mode == eQSPI_FLASH_QUAD_IO) || (bus_mode == eQSPI_FLASH_QUAD_OUTPUT) ){
			QSPI->CTRL = CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos     |
			             QSPI_QUAD_OUTPUT  << QSPI_CTRL_FRAME_MODE_Pos;
		}
	}

	for( int i=0;i<data_len;i++ ){
		if( data_read_or_write == 0 ){
			QSPI->DATA8[0] = QSPI_DUMMY_DATA;                    while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
      		data[i] = QSPI->DATA8[0];
		}else{
			QSPI->DATA8[0] = data[i];                            while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
		}
	}

	if( bus_mode > eQSPI_FLASH_STD ){
		QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
		QSPI->CTRL =  QSPI_READ_CMD_STANDARD  << QSPI_CTRL_READ_COMMAND_Pos|
		0  << QSPI_CTRL_TSHSL_Pos       |
		3  << QSPI_CTRL_DUMMY_LEN_Pos   |
		CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos   |
		QSPI_STANDARD  << QSPI_CTRL_FRAME_MODE_Pos;
	}
	
  	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
}

static void udsf_qspi_set_xip_disable(void){
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
	QSPI->CTRL =  READ_DATA  << QSPI_CTRL_READ_COMMAND_Pos|
	0  << QSPI_CTRL_TSHSL_Pos       |
	3  << QSPI_CTRL_DUMMY_LEN_Pos   |
	CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos     |
	QSPI_STANDARD  << QSPI_CTRL_FRAME_MODE_Pos;
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
}

static void udsf_qspi_set_xip_enable(eQSPI_FLASH_MODE mode){
	//uint8_t flag=0;
	if( mode == eQSPI_FLASH_DUAL_OUTPUT ){
		mode = eQSPI_FLASH_DUAL_IO;
	}else if( mode == eQSPI_FLASH_QUAD_OUTPUT ){
		mode = eQSPI_FLASH_QUAD_IO;
	}else{
		;
	}
	// xip enable
	QSPI->CS = (QSPI_CS_XIP_ON_Msk | QSPI_CS_CS_HIGH);

	if(mode == eQSPI_FLASH_DUAL_OUTPUT){
		QSPI->CTRL = ( 
		QSPI_CTRL_BOOT_SEL_Msk                                |\
		QSPI_CTRL_MSB_SEL_Msk                                 |\
		(QSPI_DUAL_OUTPUT << QSPI_CTRL_FRAME_MODE_Pos)          |\
		(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
		(QSPI_DUMMY_DATA_LEN_DUAL_OUTPUT << QSPI_CTRL_DUMMY_LEN_Pos)  |\
		(QSPI_READ_CMD_DUAL_OUTPUT << QSPI_CTRL_READ_COMMAND_Pos));
	}else if(mode == eQSPI_FLASH_DUAL_IO){	// xip 支持 flash的dual IO 模式
		QSPI->CTRL = ( 
		QSPI_CTRL_BOOT_SEL_Msk                                |\
		QSPI_CTRL_MSB_SEL_Msk                                 |\
		(QSPI_DUAL_INPUT << QSPI_CTRL_FRAME_MODE_Pos)          |\
		(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
		(QSPI_DUMMY_DATA_LEN_DUAL_IO << QSPI_CTRL_DUMMY_LEN_Pos)  |\
		(QSPI_READ_CMD_DUAL_IO << QSPI_CTRL_READ_COMMAND_Pos));
	}else if( mode == eQSPI_FLASH_QUAD_OUTPUT || mode == eQSPI_FLASH_QUAD_IO ){
		uint8_t reg_val[2];
		reg_val[0] = udsf_qspi_read_cmd(READ_REG1);
		reg_val[1] = udsf_qspi_read_cmd(READ_REG2);

		if( !(reg_val[1] & 0x2) ){ // 大多flash都是这个bit位
			reg_val[1] |= 0x2;
			udsf_qspi_send_cmd(WRITE_ENABLE);
			udsf_qspi_send_cmd(WRITE_REG_ENABLE);
			udsf_qspi_send_cmd_subcmd_data(WRITE_REG1,0,0,reg_val,2,1,eQSPI_FLASH_STD);
			//udsf_delay_ms(10);
		}
		QSPI->CTRL = ( 
		QSPI_CTRL_BOOT_SEL_Msk                                |\
		QSPI_CTRL_MSB_SEL_Msk                                 |\
		(QSPI_QUAD_OUTPUT << QSPI_CTRL_FRAME_MODE_Pos)          |\
		(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
		(QSPI_DUMMY_DATA_LEN_QUAD_OUTPUT << QSPI_CTRL_DUMMY_LEN_Pos)  |\
		(QSPI_READ_CMD_QUAD_OUTPUT << QSPI_CTRL_READ_COMMAND_Pos));
	
		if( mode == eQSPI_FLASH_QUAD_IO ){// xip 支持 flash的quad IO 模式
			QSPI->CTRL = ( 
			QSPI_CTRL_BOOT_SEL_Msk                                |\
			QSPI_CTRL_MSB_SEL_Msk                                 |\
			(QSPI_QUAD_INPUT << QSPI_CTRL_FRAME_MODE_Pos)          |\
			(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
			(QSPI_DUMMY_DATA_LEN_QUAD_IO << QSPI_CTRL_DUMMY_LEN_Pos)  |\
			(QSPI_READ_CMD_QUAD_IO << QSPI_CTRL_READ_COMMAND_Pos));
		}
	}else{
		QSPI->CTRL = ( 
		QSPI_CTRL_BOOT_SEL_Msk                                |\
		QSPI_CTRL_MSB_SEL_Msk                                 |\
		(QSPI_STANDARD << QSPI_CTRL_FRAME_MODE_Pos)          |\
		(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
		(QSPI_DUMMY_DATA_LEN_STANDARD << QSPI_CTRL_DUMMY_LEN_Pos)  |\
		(QSPI_READ_CMD_STANDARD << QSPI_CTRL_READ_COMMAND_Pos));
	}

	QSPI->CS = (QSPI_CS_XIP_ON_Msk | QSPI_CS_CS_HIGH);

	// if( flag ){
	// 	udsf_delay_ms(10);
	// }
}

/*qspi flash*/
static void udsf_spiflash_erase_fullchip(void) __attribute__((unused));
static void udsf_spiflash_erase_sector(uint32_t addr) __attribute__((unused));
static void udsf_spiflash_write_data(uint8_t* pData,uint32_t qspiAddr,int data_len) __attribute__((unused));
static void udsf_spiflash_read_data(uint8_t* pData,uint32_t qspiAddr,int data_len,eQSPI_FLASH_MODE mode) __attribute__((unused));
static  int udsf_spiflash_verify_data(uint8_t* pData,uint8_t* tmp_buff,uint32_t qspiAddr,int data_len) __attribute__((unused));

static void udsf_spiflash_write_data(uint8_t* pData8,uint32_t qspiAddr,int data_len){

	udsf_qspi_send_cmd(WRITE_ENABLE);
	
	udsf_qspi_send_cmd_subcmd_data(PAGE_PROGRAM,qspiAddr<<8,3,pData8,data_len,1,eQSPI_FLASH_STD);
	
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );
}

static void udsf_spiflash_read_data(uint8_t* pData8,uint32_t qspiAddr,int data_len,eQSPI_FLASH_MODE mode){	
	uint8_t cmd = READ_DATA;
	if( mode == eQSPI_FLASH_DUAL_OUTPUT ){
		cmd = READ_DATA_DUAL_OUTPUT;
	}else 	if( mode == eQSPI_FLASH_DUAL_IO ){
		cmd = READ_DATA_DUAL_IO;
	}else	if( mode == eQSPI_FLASH_QUAD_OUTPUT || mode == eQSPI_FLASH_QUAD_IO ){
		cmd = READ_DATA_QUAD_OUTPUT;
		if( mode == eQSPI_FLASH_QUAD_IO ){
			cmd = READ_DATA_QUAD_IO;
		}
		uint8_t reg_val[2];
		reg_val[0] = udsf_qspi_read_cmd(READ_REG1);
		reg_val[1] = udsf_qspi_read_cmd(READ_REG2);

		if( !(reg_val[1] & 0x2) ){ // 大多flash都是这个bit位
			reg_val[1] |= 0x2;
			udsf_qspi_send_cmd(WRITE_ENABLE);
			udsf_qspi_send_cmd(WRITE_REG_ENABLE);
			udsf_qspi_send_cmd_subcmd_data(WRITE_REG1,0,0,reg_val,2,1,eQSPI_FLASH_STD);
			//udsf_delay_ms(10);
		}
	}
	udsf_qspi_send_cmd_subcmd_data(cmd,qspiAddr<<8,3,pData8,data_len,0,mode);// 0-read 1-write
}

static  int udsf_spiflash_verify_data(uint8_t* pData8,uint8_t *tmp_buff,uint32_t qspiAddr,int data_len){
	int res = 0;
	
	udsf_qspi_send_cmd_subcmd_data(READ_DATA,qspiAddr<<8,3,tmp_buff,data_len,0,eQSPI_FLASH_STD);// 0-read 1-write
	
	for (int sCnt = 0; sCnt < data_len; sCnt++){
		if(tmp_buff[sCnt] != pData8[sCnt]){
			res = -1;
			break;
		}
	}
	return res;
}

static void udsf_spiflash_erase_fullchip(void){

	udsf_qspi_send_cmd(WRITE_ENABLE);
	
	udsf_qspi_send_cmd(CHIP_ERASE);

	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );
	udsf_qspi_send_cmd(WRITE_DISABLE);
}

static void udsf_spiflash_erase_sector(uint32_t addr){

	udsf_qspi_send_cmd(WRITE_ENABLE);

	udsf_qspi_send_cmd_subcmd_data(SECTOR_ERASE,addr<<8,3,NULL,NULL,1,eQSPI_FLASH_STD);
	
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );
	udsf_qspi_send_cmd(WRITE_DISABLE);
}

static void udsf_spiflash_enter_deep_sleep(void){
	udsf_qspi_send_cmd(DEEP_PD);
}

static void udsf_spiflash_opt_erase(uint32_t qspiAddr){
	udsf_qspi_send_cmd(WRITE_ENABLE);
	
	udsf_qspi_send_cmd_subcmd_data(SECURITY_ERASE,qspiAddr<<8,3,NULL,0,1,eQSPI_FLASH_STD);

	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );
	udsf_qspi_send_cmd(WRITE_DISABLE);
}

static void udsf_spiflash_opt_write(uint32_t qspiAddr,uint8_t *p_data,int data_len){

	udsf_qspi_send_cmd(WRITE_ENABLE);
	
	udsf_qspi_send_cmd_subcmd_data(SECURITY_PP,qspiAddr<<8,3,p_data,data_len,1,eQSPI_FLASH_STD);
	
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );
	udsf_qspi_send_cmd(WRITE_DISABLE);
}

static void udsf_spiflash_opt_read(uint8_t cmd,uint32_t qspiAddr,uint8_t *p_data,int data_len){
	udsf_qspi_send_cmd_subcmd_data(cmd,qspiAddr<<8,3,p_data,data_len,0,eQSPI_FLASH_STD);// 0-read 1-write
}

static uint16_t udsf_spiflash_opt_lock(uint8_t a_reg1_msk,uint8_t a_reg2_msk,uint8_t b_reg1_msk,uint8_t b_reg2_msk){
	
	uint16_t reg_read_ret;
	
	uint8_t reg_read[2];
	uint8_t reg_write[2];
	
	reg_read[0] = udsf_qspi_read_cmd(READ_REG1);
	reg_read[1] = udsf_qspi_read_cmd(READ_REG2);

	reg_read_ret = (reg_read[1]<<8)|reg_read[0];
	
	reg_write[0] = reg_read[0]  | a_reg1_msk;
	reg_write[1] = reg_read[1]  | a_reg2_msk;

	udsf_qspi_send_cmd(WRITE_ENABLE);
	udsf_qspi_send_cmd(WRITE_REG_ENABLE);
	udsf_qspi_send_cmd_subcmd_data(WRITE_REG1,0,0,reg_write,2,1,eQSPI_FLASH_STD);

	// reg_write[0] = reg_read[0]  | b_reg1_msk;
	// reg_write[1] = reg_read[1]  | b_reg2_msk;
	
	// udsf_qspi_send_cmd(WRITE_REG_ENABLE);
	// udsf_qspi_send_cmd_subcmd_data(WRITE_REG1,0,0,reg_write,2,1,eQSPI_FLASH_STD);
	//udsf_qspi_send_cmd(WRITE_DISABLE);
	return reg_read_ret;
}

#endif

